﻿Imports System.IO
Imports System.Windows
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Media.Media3D
Imports System.Windows.Controls
Namespace CoverFlow
    Friend Class Cover
        Inherits ModelVisual3D
        Implements ICover
#Region "Constants"
        Public Const CoverStep As Double = 0.4 '0.2
        Public Traslacion_x As Double = 1.5 '1.5
        Public Zoom As Double = 0.5 '0.5
        Public Traslacion_z = -1 '-1
        Public Angulo As Double = -90 '-90
        Private Estilo As Covers
        Public Shared ReadOnly AnimationDuration As TimeSpan = TimeSpan.FromMilliseconds(380)
#End Region
#Region "Fields"

        Private Shared thumbCache As IThumbnailManager
        Private ReadOnly visualModel As ModelVisual3D
        Private ReadOnly imageSource As ImageSource
        Private ReadOnly modelGroup As Model3DGroup
        Private ReadOnly rotation As AxisAngleRotation3D
        Private ReadOnly translation As TranslateTransform3D
        Private ReadOnly RotateTransform As AxisAngleRotation3D
        Private ReadOnly pos As Integer
        Private ReadOnly imageName As String
#End Region
#Region "Private stuff"

        Private Shared Function CalculateNormal(p0 As Point3D, p1 As Point3D, p2 As Point3D) As Vector3D
            Dim v0 = New Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z)
            Dim v1 = New Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z)
            Return Vector3D.CrossProduct(v0, v1)
        End Function

        Private Shared Function BuildMesh(p0 As Point3D, p1 As Point3D, p2 As Point3D, p3 As Point3D, q0 As Point, q1 As Point, _
         q2 As Point, q3 As Point) As MeshGeometry3D
            Dim mesh = New MeshGeometry3D()
            mesh.Positions.Add(p0)
            mesh.Positions.Add(p1)
            mesh.Positions.Add(p2)
            mesh.Positions.Add(p3)

            Dim normal = CalculateNormal(p0, p1, p2)
            mesh.TriangleIndices.Add(0)
            mesh.TriangleIndices.Add(1)
            mesh.TriangleIndices.Add(2)
            mesh.Normals.Add(normal)
            mesh.Normals.Add(normal)
            mesh.Normals.Add(normal)
            mesh.TextureCoordinates.Add(q3)
            mesh.TextureCoordinates.Add(q2)
            mesh.TextureCoordinates.Add(q1)

            normal = CalculateNormal(p2, p3, p0)
            mesh.TriangleIndices.Add(2)
            mesh.TriangleIndices.Add(3)
            mesh.TriangleIndices.Add(0)
            mesh.Normals.Add(normal)
            mesh.Normals.Add(normal)
            mesh.Normals.Add(normal)
            mesh.TextureCoordinates.Add(q0)
            mesh.TextureCoordinates.Add(q1)
            mesh.TextureCoordinates.Add(q2)

            mesh.Freeze()
            Return mesh
        End Function

        Private Function RectangleDx() As Double
            If imageSource.Width > imageSource.Height Then
                Return 0
            End If
            Return 1 - imageSource.Width / imageSource.Height
        End Function

        Private Function RectangleDy() As Double
            If imageSource.Width > imageSource.Height Then
                Return 1 - imageSource.Height / imageSource.Width
            End If
            Return 0
        End Function

        Private Function Tessellate() As Geometry3D
            Dim dx As Double = RectangleDx()
            Dim dy As Double = RectangleDy()
            Dim p0 = New Point3D(-1 + dx, -1 + dy, 0) '-1 + dx, -1 + dy, 0
            Dim p1 = New Point3D(1 - dx, -1 + dy, 0) '1 - dx, -1 + dy, 0
            Dim p2 = New Point3D(1 - dx, 1 - dy, 0) '1 - dx, 1 - dy, 0
            Dim p3 = New Point3D(-1 + dx, 1 - dy, 0) '-1 + dx, 1 - dy, 0
            Dim q0 = New Point(0, 0)
            Dim q1 = New Point(1, 0)
            Dim q2 = New Point(1, 1)
            Dim q3 = New Point(0, 1)
            Return BuildMesh(p0, p1, p2, p3, q0, q1, _
             q2, q3)
        End Function

        Private Function TessellateMirror() As Geometry3D
            Dim dx As Double = RectangleDx()
            Dim dy As Double = RectangleDy()
            Dim p0 = New Point3D(-1 + dx, -3 + 3 * dy, 0)
            Dim p1 = New Point3D(1 - dx, -3 + 3 * dy, 0)
            Dim p2 = New Point3D(1 - dx, -1 + dy, 0)
            Dim p3 = New Point3D(-1 + dx, -1 + dy, 0)
            Dim q0 = New Point(0, 1)
            Dim q1 = New Point(1, 1)
            Dim q2 = New Point(1, 0)
            Dim q3 = New Point(0, 0)
            Return BuildMesh(p0, p1, p2, p3, q0, q1, _
             q2, q3)
        End Function

        Private Shared Function LoadImageSource(info As ImageInfo) As ImageSource
            If thumbCache Is Nothing Then
                Throw New InvalidOperationException("crea un nuevo cache con Flow.cache = new thumbnailmanager e importa la libreria.")
            End If
            Return thumbCache.GetThumbnail(info.Host, info.Path)
        End Function

        Private Function LoadImage(imSrc As ImageSource) As Material

            Estilo = New Covers
            Estilo.CoverImg.Source = imSrc

            Return New DiffuseMaterial(New VisualBrush(Estilo))

        End Function

        Private Function LoadImageMirror(imSrc As ImageSource) As Material

            Dim Shad As New Covers



            Shad.Opacity = 0.6
            Shad.CoverImg.Source = imSrc

            Return New DiffuseMaterial(New VisualBrush(Shad))

        End Function

        Private Function RotationAngle(index As Integer) As Double
            

            Return Math.Sign(pos - index) * Angulo
        End Function

        Private Function TranslationX(index As Integer) As Double
            Return pos * CoverStep + Math.Sign(pos - index) * Traslacion_x
        End Function

        Private Function TranslationZ(index As Integer) As Double
            If pos = index Then

                Return Zoom
            Else
                Return Traslacion_z
            End If

        End Function


#End Region

        Public Sub New(info As ImageInfo, coverPos As Integer, currentPos As Integer, model As ModelVisual3D)

            pos = coverPos

            visualModel = model

            imageSource = LoadImageSource(info)
            modelGroup = New Model3DGroup()
            modelGroup.Children.Add(New GeometryModel3D(Tessellate(), LoadImage(imageSource)))
            modelGroup.Children.Add(New GeometryModel3D(TessellateMirror(), LoadImageMirror(imageSource)))

            rotation = New AxisAngleRotation3D(New Vector3D(0, 1, 0), RotationAngle(currentPos))
            translation = New TranslateTransform3D(TranslationX(currentPos), 0, TranslationZ(currentPos))


            Dim transformGroup = New Transform3DGroup()
            transformGroup.Children.Add(New RotateTransform3D(rotation))
            transformGroup.Children.Add(translation)


            modelGroup.Transform = transformGroup

            Content = modelGroup

            visualModel.Children.Add(Me)
        End Sub

        Public Shared WriteOnly Property Cache() As IThumbnailManager
            Set(value As IThumbnailManager)
                thumbCache = value
            End Set
        End Property

        Public Sub Animate(index As Integer, animate__1 As Boolean) Implements ICover.Animate
            If animate__1 OrElse rotation.HasAnimatedProperties Then
                Dim rotateAnimation = New DoubleAnimation(RotationAngle(index), AnimationDuration)
                Dim xAnimation = New DoubleAnimation(TranslationX(index), AnimationDuration)
                Dim zAnimation = New DoubleAnimation(TranslationZ(index), AnimationDuration)
                rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, rotateAnimation)
                translation.BeginAnimation(TranslateTransform3D.OffsetXProperty, xAnimation)
                translation.BeginAnimation(TranslateTransform3D.OffsetZProperty, zAnimation)

            Else
                rotation.Angle = RotationAngle(index)
                translation.OffsetX = TranslationX(index)
                translation.OffsetZ = TranslationZ(index)
            End If
        End Sub


        Public Function Matches(mesh As MeshGeometry3D) As Boolean Implements ICover.Matches
            For Each part As GeometryModel3D In modelGroup.Children
                If part.Geometry.Equals(mesh) Then
                    Return True
                End If
            Next
            Return False
        End Function

        Public Sub Destroy() Implements ICover.Destroy
            visualModel.Children.Remove(Me)
        End Sub


    End Class
End Namespace
